package org.flowable.pz.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.flowable.pz.entity.dto.FlowableDefinitionDto;
import org.flowable.pz.entity.vo.FlowableXmlVo;
import org.flowable.pz.exception.FlowableCustomException;
import org.flowable.pz.mapper.FlowableDefinitionMapper;
import org.flowable.pz.service.FlowableDefinition;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.persistence.entity.DeploymentEntity;
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.flowable.engine.repository.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.Valid;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * flowable 相关操作
 * */
@Component
@Slf4j
@Validated
public class FlowableDefinitionImpl implements FlowableDefinition {

    /**
     * RepositoryService 是 Flowable 引擎中的服务之一，用于管理流程定义的部署和查询。
     * 它提供了一系列方法，用于管理流程定义的生命周期、与流程定义相关的资源、以及对流程定义的查询操作。
     * */
    @Autowired
    private RepositoryService repositoryService;

    /**
     * RuntimeService是Flowable引擎中的一个服务接口，用于管理流程实例的运行时状态和相关操作
     * */
    @Autowired
    private RuntimeService runtimeService;

    /**
     * TaskService是Flowable引擎中的一个服务接口，用于处理任务相关的操作和数据。
     * */
    @Autowired
    private TaskService taskService;

    @Autowired
    private FlowableDefinitionMapper flowableDefinitionMapper;

    private final String xmlSuffix = ".bpmn20.xml";

    /**
     * 部署流程定义   file 也就是流程文件，后缀要 .bpmn20.xml
     */
    @Override
    public void deployment(MultipartFile file) {
        DeploymentBuilder deployment = repositoryService.createDeployment();
        Deployment deploy;
        try (InputStream is = file.getInputStream()){
            deployment.addInputStream(file.getOriginalFilename(), is);
            deploy = deployment.deploy();
        }catch (IOException e){
            log.info("流程部署异常：{}", e.getMessage());
            throw new FlowableCustomException("流程部署异常");
        }

        //检查下流程定义是否成功
        checkDeploy(deploy);
        log.info("流程部署成功！！！");
    }

    @Override
    public void deployment(@Valid FlowableXmlVo flowXmlVo){
        //部署流程
        Deployment deploy = repositoryService.createDeployment()
                .name(flowXmlVo.getName())
                .addString(flowXmlVo.getName().toLowerCase().endsWith(xmlSuffix)?flowXmlVo.getName():flowXmlVo.getName()+xmlSuffix , flowXmlVo.getXml())
                .category(flowXmlVo.getCategory())
                .deploy();
        checkDeploy(deploy);

        //流程定义设置category
        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getParentDeploymentId())
                .singleResult();
        repositoryService.setProcessDefinitionCategory(definition.getId(), flowXmlVo.getCategory());

        log.info("流程部署成功！！！");
    }

    @Override
    public List<FlowableDefinitionDto> definitionList(String name, String type) {
        return flowableDefinitionMapper.definitionDtoList(type, name);
    }

    @Override
    public void suspend(String definitionId) {
        if(repositoryService.isProcessDefinitionSuspended(definitionId)){
            repositoryService.activateProcessDefinitionById(definitionId);
        }else{
            repositoryService.suspendProcessDefinitionById(definitionId);
        }
    }


    /**
     * 通过获取流程定义，来判断部署是否成功
     * */
    private void checkDeploy(Deployment deploy){
        if(deploy instanceof DeploymentEntity){
            List<ProcessDefinitionEntity> das = ((DeploymentEntity) deploy).getDeployedArtifacts(ProcessDefinitionEntity.class);
            if(das != null && !das.isEmpty()){
                return;
            }
        }
        throw new FlowableCustomException("流程定义失败！！！！");
    }
}
